package test2.redis;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

import redis.clients.jedis.Jedis;
import test2.redis.RedisDistributedLock.LockService;

public class LockTest {
	
	Jedis jedis = new Jedis();
	
	long timeout = 3000L;
	String key = "aaa";
	
	@Test
	public void test1() {
		
		String result = jedis.set(key, (now() + timeout) + "");
		System.out.println("result="+result);
		//TODO
//		jedis.del("aaa");
		jedis.close();
	}
	
	/**
	 * 模拟场景：
	 * 	第一个获得锁的请求由于各种原因未能及时释放，
	 * 	后来的几个请求获取锁失败后同时判断原来的锁超时并先后删掉原来的锁，自己获取新的锁
	 */
	@Test
	public void test2() {
		while(true) {
			Long result = jedis.setnx(key, (now() + timeout) + "");
			System.out.println("result="+result);
			if(result==0) {
				System.out.println("锁失败");
				String a = jedis.get(key);
				long b = Long.parseLong(a);
				if(now()>b) {
					System.out.println("当前时间大于当前锁过期时间，证明当前锁已经失效，可以删除当前锁变为自己的锁");
					try {
						//睡5秒，模拟并发，多个请求同时判断出锁过期，准备删除
						Thread.sleep(8000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					Long c = jedis.del(key);
					System.out.println("删除结果="+c);
					Long d = jedis.setnx(key, (now() + timeout) + "");
					System.out.println("锁结果="+d);
					break;
				} else {
					try {
						Thread.sleep(300);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			} else {
				break;
			}
		}
		//TODO 业务逻辑
		System.out.println("业务逻辑");
//		jedis.del(key);
		jedis.close();
	}
	
	/**
	 * 通过getSet解决并发问题
	 */
	@Test
	public void test3() {
		while(true) {
			Long result = jedis.setnx(key, (now() + timeout) + "");
			System.out.println("result="+result);
			if(result==0) {
				System.out.println("锁失败");
				String a = jedis.get(key);
				long b = Long.parseLong(a);
				if(now()>b) {
					System.out.println("当前时间大于当前锁过期时间，证明当前锁已经失效，可以删除当前锁变为自己的锁");
					try {
						//睡5秒，模拟并发，多个请求同时判断出锁过期，准备删除
						Thread.sleep(8000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					String c = jedis.getSet(key, (now() + timeout) + "");
					System.out.println("原来的过期时间="+c);
					long d = Long.parseLong(c);
					System.out.println("当前的时间="+now());
					if(now()>d) {
						break;
					}
				} 
			} else {
				break;
			}
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//TODO 业务逻辑
		System.out.println("业务逻辑");
//		jedis.del(key);
		jedis.close();
	}
	
	private long now() {
		return System.currentTimeMillis();
	}
	
	static ExecutorService threadpool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
	
	@Test
	public void test4() {
		
	}
	
	public static void main(String[] args) {
		//---初始化---
		Jedis jedis = new Jedis();
		jedis.flushDB();
		jedis.set("tv", "2");
		jedis.close();
		//---初始化结束---
		for(int i=0;i<5;i++) {
			threadpool.submit(new Runnable() {
				@Override
				public void run() {
					new RedisDistributedLock("tvkey").lock(new LockService() {
						@Override
						public void deal() {
							Jedis jedis = new Jedis();
							int num = Integer.parseInt(jedis.get("tv"));
							if(num>0) {
								jedis.decr("tv");
								System.out.println("原库存"+num+",抢到1个，还剩"+(num-1)+"个");
							} else {
								System.out.println("抢光了");
							}
							jedis.close();
						}
					});
				}
			});
		}
		threadpool.shutdown();
	}
	
	@Test
	public void test5() {
		jedis.set("tv", "3");
		jedis.close();
	}

}
